package com.cyou.nad.qb.task;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cyou.nad.dao.PojoPage;
import com.cyou.nad.mongo.orm.config.DBChooser;
import com.cyou.nad.mongo.orm.core.MongoDBTemplate;
import com.cyou.nad.mongo.orm.query.Query;
import com.cyou.nad.mongo.orm.query.QueryOperators;
import com.cyou.nad.qb.task.constants.QbTaskConstants;
import com.cyou.nad.utils.DateUtils;
import com.cyou.qb.common.domain.StatActiveDay;
import com.cyou.qb.common.mongo.po.ClickLog;
import com.cyou.qb.common.mongo.po.DrawLog;
import com.cyou.qb.common.service.StatisticsService;

/**
 * mongo相关定时任务<br>
 * 分页实现
 * @author zoudongchao
 */
@Service("mongoManage")
public class MongoManage {
	/*
	 * 静态变量
	 * 获取ApplicationContext Mongo工具 和 日志Logger
	 */
	@Autowired
	private MongoDBTemplate template = null;
	private static Logger logger = Logger.getLogger(MongoManage.class);
	@Resource(name="StatisticsServiceImpl")
	private StatisticsService statisticsService;
	private int pageSize = QbTaskConstants.MONGO_QUERY_PAGESIZE;
	/**
	 * <p>备份点击log</p>
	 */
	public void backupClickLog() {
		this.backupLogHistory(ClickLog.class, QbTaskConstants.MONGO_DB, QbTaskConstants.MONGO_COLLECTION_CLICK,
				QbTaskConstants.MONGO_COLLECTION_CLICK_BACKUP, QbTaskConstants.MONGO_DAYCOUNT_DELETE);
	}

	/**
	 * <p>备份抽奖log</p>
	 */
	public void backupDrawLog() {
		this.backupLogHistory(DrawLog.class, QbTaskConstants.MONGO_DB, QbTaskConstants.MONGO_COLLECTION_DRAW,
				QbTaskConstants.MONGO_COLLECTION_DRAW_BACKUP, QbTaskConstants.MONGO_DAYCOUNT_DELETE);
	}

	/**
	 * 删除6个月前的日志
	 */
	public void deleteBackupClickLog() {
		this.deleteLogHistory(ClickLog.class, QbTaskConstants.MONGO_DB, QbTaskConstants.MONGO_COLLECTION_CLICK, Calendar.MONTH, 6);
	}
	
	public void deleteBackupDrawLog() {
		this.deleteLogHistory(DrawLog.class, QbTaskConstants.MONGO_DB, QbTaskConstants.MONGO_COLLECTION_CLICK, Calendar.MONTH, 6);
	}
	
	/**
	 * <p>统计做日mongo数据到数据库</p>
	 * 应当在今日凌晨执行
	 */
	public void mongoStatisticsYestoday() {
		Date today = org.apache.commons.lang.time.DateUtils.truncate(new Date(), Calendar.DATE);
		Date yestoday = DateUtils.addDayWithTime(today, -1);
		mongoStatistics(yestoday, today);
	}
	
	/****************************************for test***********************************************/
	/**
	 * <p>统计做日mongo数据到数据库</p>
	 * 一分钟执行，统计到当前时间的数据，用以测试
	 */
//	public void mongoStatisticsToNow() {
//		Date today = org.apache.commons.lang.time.DateUtils.truncate(new Date(), Calendar.DATE);
//		Date yestoday = DateUtils.addDayWithTime(today, -1);
//		mongoStatistics(yestoday, new Date());
//	}
	
	/**************************************工具方法*****************************************/

	/**
	 * <p>备份N天前的mongo数据到备份mongo库，删除原库数据</p>
	 * 每天执行
	 * @param T 需要备份的实体类
	 * @param dbName 源mongo数据库名
	 * @param collection 集合名
	 * @param backupCollection 备份mongo数据库名
	 * @param dayCount 备份N天前
	 */
	@SuppressWarnings("rawtypes")
	protected void backupLogHistory(Class T, String dbName, String collection, String backupCollection, int dayCount) {

		logger.info("[MongoManage][backup]db:" + dbName + " collection:" + collection + " days:" + dayCount
				+ " start...");
		Date boundary = DateUtils.addDayWithTime(
				org.apache.commons.lang.time.DateUtils.truncate(new Date(), Calendar.DATE), -dayCount);
		PojoPage<Object> page = new PojoPage<Object>();
		
		//设置DBChooser
		DBChooser source = DBChooser.getDbAndCollection(dbName, collection);
		DBChooser backup = DBChooser.getDbAndCollection(dbName, backupCollection);

		//1.删除备份表中    N+1天前至N天前的原表数据
		Query query = new Query(T);
		query.addCondition("createDate", QueryOperators.LT, boundary);
		query.and("createDate", QueryOperators.GTE, DateUtils.addDayWithTime(boundary, -1));
		query.pageSize(pageSize);
		
		//删除一部分之后就要重新计算一次
		int count = template.getCount(backup, query);
		while(count > 0){
			query.pageNum(1);//因为会删除，所以始终查询第一页
			page = template.query(backup, query);
			template.deleteAll(backup, page.getData());
			count = count - page.getData().size();
		}
		
		//2. 分页查询，将原数据备份至备份表
		query = new Query(T);
		query.addCondition("createDate", QueryOperators.LT, boundary);
		query.pageSize(pageSize);
		
		count = template.getCount(source, query);
		page = new PojoPage<Object>(1, count, pageSize, null);
		for (int i=0; i<page.getTotalPageCount(); i++) {//如果count为0，则totalPageCount也为0
			query.pageNum(i+1);
			page = template.query(source, query);
			template.saveAll(backup, page.getData());
		}
		
		//3. 删除原数据
		while (count > 0) {
			query.pageNum(1);
			page = template.query(source, query);
			template.deleteAll(source, page.getData());
			count = count - page.getData().size();
		}

		logger.info("[MongoManage][backup]db:" + dbName + " collection:" + collection + " days:" + dayCount
				+ " finish...");
	}

	/**
	 * <p>删除mongo过期日志</p>
	 * @author zoudongchao
	 * 
	 * @param T mongo日志对应的实体类
	 * @param dbName mongo db名
	 * @param collection db名
	 * @param calendarField 天、月、年等
	 * @param count 需要删除N前的日志
	 * @return 删除记录条数
	 */
	@SuppressWarnings({ "rawtypes", "deprecation" })
	protected int deleteLogHistory(Class T, String dbName, String collection, int calendarField, int dayCount) {
		logger.info("[MongoManage][deleteLogHistory]db:" + dbName + " collection:" + collection + " start...");
		//获取日期
		Date today = org.apache.commons.lang.time.DateUtils.truncate(new Date(), Calendar.DATE);//时分秒归零
		Date boundary = org.apache.commons.lang.time.DateUtils.add(today, calendarField, -dayCount);
		//查询
		DBChooser chooser = DBChooser.getDbAndCollection(dbName, collection);
		Query query = new Query(T);
		query.addCondition("createDate", QueryOperators.LT, boundary);
		query.pageSize(pageSize);
		
		int count = template.getCount(chooser, query);
		PojoPage<Object> page = new PojoPage<Object>(1, count, pageSize, null);
		
		while (count > 0) {
			query.pageNum(1);
			page = template.query(chooser, query);
			template.deleteAll(chooser, page.getData());
			count = count -  page.getData().size();
		}
	
		logger.info("deleted " + count + " records");
		logger.info("[MongoManage][deleteLogHistory]db:" + dbName + " collection:" + collection + " finish...");
		
		return count;
	}

	/**
	 * <p>mongo数据统计</p>
	 * 输出到mysql表<br>
	 * 统计DrawLog<br>
	 * 活动参与ID 活动抽奖人次 活动G币回收 活动G币支出
	 */
	@SuppressWarnings({ "rawtypes"})
	protected void mongoStatistics(Date start, Date end){
		logger.info("start to count mongo statistics to mysql...");
		/*
		 * 1. 查找当日mongo数据（昨日凌晨至今日凌晨）
		 *    读mongo得到大部分信息
		 */
		//活动id与对应非重复passport列表  一对多  统计参与id数
		Map<Integer, List<String>> idPassportPair = new HashMap<Integer,List<String>>();
		//活动id与数据统计实体 一对一
		Map<Integer, StatActiveDay> idStatActiveDayPair = new HashMap<Integer, StatActiveDay>();
		
		DBChooser chooser = DBChooser.getDbAndCollection(QbTaskConstants.MONGO_DB, QbTaskConstants.MONGO_COLLECTION_DRAW);
		
		Query query = new Query(DrawLog.class);
		query.addCondition("createDate", QueryOperators.GTE, start);
		query.and("createDate", QueryOperators.LT, end);
		query.pageSize(pageSize);
		
		int count = template.getCount(chooser, query); 
		
		PojoPage<DrawLog> drawPage =  new PojoPage<DrawLog>(1, count, pageSize, null);
		
		for (int i=0; i<drawPage.getTotalPageCount(); i++) {
			query.pageNum(i+1);
			drawPage = template.query(chooser, query);
			
			//数据处理
			List<DrawLog> drawList = drawPage.getData();
			for (DrawLog drawLog : drawList) {//一条drawLog代表着一个参与次数
				int activeId = drawLog.getActiveId();
				List<String> passportList = idPassportPair.get(activeId);
				StatActiveDay statActiveDay = idStatActiveDayPair.get(activeId);
				if (statActiveDay == null) {//尚未有该活动的信息 创建
					statActiveDay = new StatActiveDay();
					statActiveDay.setActiveId(activeId);
				}
				statActiveDay.setTakeNum(statActiveDay.getTakeNum()+1);//参与人数加以1  起初为0
				//确定参与id数
				if (passportList == null){
					passportList = new ArrayList<String>();
				}
				if (!passportList.contains(drawLog.getPassport())) {
					//参与ID数加一
					passportList.add(drawLog.getPassport());
					statActiveDay.setJoinNum(statActiveDay.getJoinNum()+1);//参与id数加1
				}
				idPassportPair.put(activeId, passportList);
				//回收g币
				statActiveDay.setgIn(statActiveDay.getgIn()+drawLog.getgCost());
				//更新
				idStatActiveDayPair.put(activeId, statActiveDay);
			}
		}
		/*
		 * 2. 读数据库获得G币输出 同时入库
		 */
		Iterator it = idStatActiveDayPair.values().iterator();
		while (it.hasNext()) {
			StatActiveDay statActiveDay = (StatActiveDay)it.next();
			int gOut = statisticsService.findActiveGOut(statActiveDay.getActiveId(), start, end);
			statActiveDay.setgOut(gOut);
			statActiveDay.setDate(start);//统计的是昨天的数据
			//store to db
			statisticsService.saveOrUpdateOneStatistics(statActiveDay);
		}
		logger.info("count mongo statistics to mysql end");
	}
	
	public MongoDBTemplate getTemplate() {
		return template;
	}
}
